ZF.add('dom-style', function(Z) {

    var D = Z.Dom,
        B = Z.Browser,
        S = Z.String,

        doc = document,
        docEl = doc.documentElement,
        STYLE = 'style',
        DISPLAY = 'display',
        NONE = 'none',
        EMPTY = '',
        WIDTH = 'width',
        HEIGHT = 'height',
        HIDE_FOCUS = 'hideFocus',
        OUTLINE = 'outline',
        OPACITY = 'opacity',
        FILTERS = 'filters',
        CURRENT_STYLE = 'currentStyle',
        CSS_FLOAT = 'cssFloat',
        STYLE_FLOAT = 'styleFloat',
        DEFAULT_VIEW = 'defaultView',
        GET_COMPUTED_STYLE = 'getComputedStyle',
        
        hasOpacity = doc.getElementsByTagName('html')[0][STYLE][OPACITY],
        RE_ALPHA = /alpha\(opacity=([\d.]+)\)/i,
        RE_WH = /^(?:width|height)/,
        RE_LT = /^(?:left|top)/,
        RE_NEED_UNIT = /^(?:width|height|top|left|right|bottom|margin|padding)/i,

        Properties = {
            'float' : docEl[STYLE][CSS_FLOAT] == null ? STYLE_FLOAT : CSS_FLOAT
        };

    Z.extend(D, {

        getComputedStyle : (doc[DEFAULT_VIEW] || {})[GET_COMPUTED_STYLE] ? function(el, name) {
            var ret = null;
            if (el[STYLE]) {
                var defaultView = el.ownerDocument[DEFAULT_VIEW];
                if (defaultView) {
                    var computed = defaultView[GET_COMPUTED_STYLE](el, null);
                    ret = computed ? computed.getPropertyValue(S.hyphenate(name)) : null;
                    //ret = computed ? computed[S.hyphenate(name)] : null;
                }
            }
            return ret;
        } : function(el, name) {
            var ret = null;

            if (el[CURRENT_STYLE]) {
                ret = el[CURRENT_STYLE][name];
            }

            if (RE_WH.test(name)) {
                ret = D[name](el) + 'px';
            } else {

            }

            return ret;
        },

        // TODO
        css : function(selector, name, value) {

            if (Z.isPlainObject(name)) {
                for (var k in name) {
                    D.css(selector, k, name[k]);
                }
                return this;
            }

            var el = D.get(selector);
            
            name = Properties[name] || name;
            
            // setter
            if (arguments.length > 2) {
                if (value === null || value === undefined) {
                    value = EMPTY;
                } else if(!isNaN(value) && RE_NEED_UNIT.test(name)) {
                    value += 'px';
                }

                if (el && el[STYLE]) {
                    name.set ? name.set(el, value) : (el[STYLE][name] = value);
                }

                return this;
            } else { // get
                var ret = EMPTY;

                if (el && el[STYLE]) {
                    ret = name.get ? name.get(el) : el[STYLE][name];
                }

                if (ret == EMPTY && !name.get) {
                    ret = _getStyle(el, name, D.getComputedStyle(el, name));
                }

                return ret === undefined ? EMPTY : ret;
            }
        },
        
        width : function(selector, value) {
            if (arguments.length > 1) {
                D.css(selector, WIDTH, value);
            } else {
                return _getSize(selector, WIDTH);
            }
        },
        
        height : function(selector, value) {
            if (arguments.length > 1) {
                D.css(selector, HEIGHT, value);
            } else {
                return _getSize(selector, HEIGHT);
            }
        },
        
        show : function(selector, isBlock) {
            //return D.css(D.get(selector), DISPLAY, isBlock ? 'block' : EMPTY);
            D.query(selector).each(function(el) {
                if (el && D.css(el, DISPLAY) === NONE) {
                    D.css(el, DISPLAY, isBlock ? 'block' : EMPTY);
                }
            });
            return this;
        },
        
        hide : function(selector) {
            //return D.css(D.get(selector), DISPLAY, NONE);
            D.query(selector).each(function(el) {
                if (el && D.css(el, DISPLAY) !== NONE) {
                    D.css(el, DISPLAY, NONE);
                }
            });
            return this;
        },
        
        hideOutline : B.ie ? function(selector) {
            D.query(selector).each(function(el) {
                if (el && el[HIDE_FOCUS] !== true) {
                    el[HIDE_FOCUS] = true
                }
            });
            return this;
        } : function(selector) {
            D.query(selector).each(function(el) {
                if (el && D.css(el, OUTLINE) !== NONE) {
                    D.css(el, OUTLINE, NONE);
                }
            });
            return this;
        }

    });


    function _getSize(selector, type) {
        var el = D.get(selector),
            which = type === WIDTH ? ['Left', 'Right'] : ['Top', 'Bottom'],
            val = type === WIDTH ? el.offsetWidth : el.offsetHeight;

        Z.each(which, function(v) {
            val -= (parseInt(D.getComputedStyle(el, 'border' + v + 'Width') || 0) + parseInt(el, D.getComputedStyle('padding' + v)) || 0);
        });

        return val;
    }


    function _getStyle(el, key, val) {
        var offset, ret = val;
        
        // 1. 当没有设置 style.left 时，getComputedStyle 在不同浏览器下，返回值不同
        //    比如：firefox 返回 0, webkit/ie 返回 auto
        // 2. style.left 设置为百分比时，返回值为百分比
        // 对于第一种情况，如果是 relative 元素，值为 0. 如果是 absolute 元素，值为 offsetLeft - marginLeft
        // 对于第二种情况，大部分类库都未做处理，属于“明之而不 fix”的保留 bug
        if (ret === 'auto' && RE_LT.test(key)) {
            ret = 0;
            if (Z.inArray(D.css(el, 'position'), ['absolute', 'fixed'])) {
                offset = el[key === 'left' ? 'offsetLeft' : 'offsetTop'];

                // ie8 下，elem.offsetLeft 包含 offsetParent 的 border 宽度，需要减掉
                if (B.ie8 || B.opera) {
                    offset -= parseInt(D.css(el.offsetParent, 'border-' + key + '-width')) || 0;
                }

                ret = offset - (parseInt(D.css(el, 'margin-' + key)) || 0);
            }
        }

        return ret;
    }

    var hasOpacity = doc.getElementsByTagName('html')[0][STYLE][OPACITY] != null,
        reAlpha = /alpha\(opacity=([\d.]+)\)/i;

    Properties[OPACITY] = {

        get : function(el) {
            var val = 100;
            try {
                val = el[FILTERS]['DXImageTransform.Microsoft.Alpha'][OPACITY];
            } catch(e) {
                try {
                    val = el[FILTERS]['alpha'][OPACITY];
                } catch(ex) {
                }
            }
            return val / 100;
        },
        
        set : function(el, val) {
            var style = el[STYLE], currentStyle = el[CURRENT_STYLE];

            if (!currentStyle || !currentStyle.hasLayout) {
                style.zoom = 1;
            }

            if (hasOpacity) {
                style[OPACITY] = val;
            } else {
                val = (val == 1) ? '' : 'alpha(opacity=' + val * 100 + ')';
		        var filter = style.filter || D.getComputedStyle(el, 'filter') || '';
		        style.filter = RE_ALPHA.test(filter) ? filter.replace(RE_ALPHA, val) : filter + val;
            }
        }

    };

}, { requires : ['browser', 'dom-query'] });
